#ifndef AFCORE_COMMON_ALGORITHM_MPMC_QUEUE_
#define AFCORE_COMMON_ALGORITHM_MPMC_QUEUE_

#include <condition_variable>
#include <mutex>

#include "circular_queue.h"
#include "duration.h"

namespace afcore {

/// @brief  MPMC Queue (阻塞)
template<typename T>
class CMpmcQueue {
public:
  using RItemType = T;

  /// @brief  构造函数 默认移除
  CMpmcQueue() = delete;
  /// @brief  构造函数 显示
  /// @param  capacity    最大容量
  explicit CMpmcQueue(size_t capacity)
    : q_(capacity) {
  }

  /// @brief  入队 阻塞
  /// @param  item    元素
  void Enqueue(T&& item) {
    {
      std::unique_lock<std::mutex> lock(queue_mutex_);
      de_cv_.wait(lock,
          [this] () {
            return !this->q_.Full();
          });
      q_.EnQueue(std::move(item));
    }
    en_cv_.notify_one();
  }

  /// @brief  入队 非阻塞
  /// @param  item    元素
  void EnqueueNoWait(T&& item) {
    {
      std::unique_lock<std::mutex> lock(queue_mutex_);
      q_.EnQueue(std::move(item));
    }
    en_cv_.notify_one();
  }

  /// @brief  出队 阻塞
  /// @param  [out]   dequeue_item    出队元素
  /// @param  wait_duration           等待间隔
  /// @return true 出队成功
  /// @return false 出队失败 队列为空
  bool Dequeue(T& dequeue_item, RMilliseconds wait_duration) {
    {
      std::unique_lock<std::mutex> lock(queue_mutex_);
      if (!en_cv_.wait_for(lock, wait_duration,
          [this] () {
            return !this->q_.Empty();
          })) {
        return false;
      }
      dequeue_item = std::move(q_.Front());
      q_.DeQueue();
    }
    de_cv_.notify_one();
    return true;
  }

  /// @brief  获取当前累计越界的数量
  /// @return 当前累计越界的数量
  size_t GetOverrunCount() {
    std::unique_lock<std::mutex> lock(queue_mutex_);
    return q_.GetOverrunCount();
  }

private:
  std::mutex queue_mutex_;        ///< 队列互斥锁
  std::condition_variable en_cv_; ///< 入队条件
  std::condition_variable de_cv_; ///< 出队条件
  CCircularQueue<T> q_;           ///< 队列
};

} // !namespace afcore

#endif //! AFCORE_COMMON_ALGORITHM_MPMC_QUEUE_